import { MathUtils, Object3D, PointLight, TextureLoader, Vector3 } from "three";
import { App, ObjWander, Poi2, Point, Polyline, Polyline2 } from "../Engine";
import { Lensflare, LensflareElement } from "three/examples/jsm/Addons";
import Const from "../application/constants/Const";
import Events from "../application/constants/Events";
/**
 * 无人机模拟飞行
 */
export default class FlightSimulator {
    private app: App;
    private objWandered: Object3D; //漫游的物体
    private simulatorData: { collisionObjs?: Array<Object3D>, sidewipeDistance?: number, flickerImg: string, startPoiImg: string, endPoiImg: string, airportPosition: Point, airportImg: string, simulatorInitPosition: Point, backHeight: number, timeFactor: number }; //collisionObjs是场景中会和漫游物体发生碰撞的物体数组，sidewipeDistance是擦边的距离
    private wanderLine: Polyline;
    private realTravelLine: Polyline;
    private toStratLine: Polyline;
    private backwayLine: Polyline;
    private flyedPolyline: Polyline2; //无人机真正飞过的路线组件
    private hasCollision = false;
    private startPOI: Poi2;
    private endPOI: Poi2;

    public constructor(objWandered: Object3D, simulatorData: { collisionObjs?: Array<Object3D>, sidewipeDistance?: number, flickerImg: string, startPoiImg: string, endPoiImg: string, airportPosition: Point, airportImg: string, simulatorInitPosition: Point, backHeight: number, timeFactor: number }) {
        this.app = App.getInstance();
        this.objWandered = objWandered;
        this.simulatorData = simulatorData;

        this.app.on(Events.CameraChange, this.scaleBrokenLine.bind(this), this);
        this.app.on(Events.Render, this.scalePoi.bind(this), this);
    }

    private getCameraDistance() {
        let cameraPosition = this.app.camera.position;
        let lookTarget = this.app.camera.lookAtTarget;
        const distance = cameraPosition.distanceTo(lookTarget);
        return distance;
    }

    private scaleBrokenLine() {
        if (!this.toStratLine || !this.backwayLine) {
            return;
        }
        let distance = this.getCameraDistance();
        let scaleFactor = distance / 500;
        this.setBrokendLine(this.backwayLine, scaleFactor);
        this.setBrokendLine(this.toStratLine, scaleFactor);
    }

    private scalePoi() {
        if (!this.startPOI || !this.endPOI) {
            return;
        }
        let distance = this.getCameraDistance();
        let poiScaleFactor = distance / 150;
        this.startPOI.scale.set(poiScaleFactor, poiScaleFactor, poiScaleFactor);
        this.endPOI.scale.set(poiScaleFactor, poiScaleFactor, poiScaleFactor)
    }

    private setBrokendLine(line: Polyline, scaleFactor: number) { //设置线条的虚线属性
        line.material.dashSize = 1 * scaleFactor; // 动态调整实线长度
        line.material.gapSize = 0.5 * scaleFactor; // 动态调整间隙长度
        line.material.needsUpdate = true; // 标记材质需更新
    }

    private initPoi(poiConfig, poiImg) {
        const poi = new Poi2(poiConfig);
        poi.updateTextLayout('image-only');
        poi.updateShapeTexture(poiImg);
        poi.renderOrder = 6;
        this.app.add(poi);
        return poi;
    }

    private setPoi(startPoint: Point, endPoint: Point) {
        let poiConfig = {
            position: startPoint,
            name: '',
            baseImageSize: 100,
            showText: false,
            center: [0.5, 0.0],
            depthTest: true,
            defaultShape: 'square',
            shapeSize: 2.5,
            shapeColor: '#FF6B6B',
            shapeStrokeWidth: 0,
        };
        this.startPOI = this.initPoi(poiConfig, this.simulatorData.startPoiImg);

        poiConfig.position = endPoint;
        this.endPOI = this.initPoi(poiConfig, this.simulatorData.endPoiImg);

        poiConfig.position = this.simulatorData.airportPosition;
        poiConfig.center = [0.5, 0.5];
        let airPotPot = this.initPoi(poiConfig, this.simulatorData.airportImg);
        airPotPot.position.z += 2.5;
    }

    private addFlyLines(linePath, path, lineWidth, stencilRef) {
        let pathLineData = {
            pointArray: linePath,  //多边形的顶点数组
            lineWidth: lineWidth,  //线的宽度
            depthTest: true,
            color: '#0000FF',
            blockedColor: '#0000FF',
            transparent: true,
        };
        // @ts-ignore
        this.wanderLine = new Polyline(pathLineData);
        this.wanderLine.renderOrder = 2;
        this.wanderLine.filterStencil(stencilRef);
        this.app.add(this.wanderLine);

        let dashLineData = {
            pointArray: [this.simulatorData.airportPosition, this.simulatorData.simulatorInitPosition, linePath[0]],  //多边形的顶点数组
            lineWidth: lineWidth,  //线的宽度
            dashed: true,  //开启虚线
            dashSize: 0.5,      // 实线段的长度（默认1）
            gapSize: 0.5,       // 空白间隙的长度（默认1）
            depthTest: true,
            color: '#0000FF',
            blockedColor: '#0000FF',
            transparent: true,
        };
        this.toStratLine = new Polyline(dashLineData);
        this.toStratLine.renderOrder = 2;
        this.toStratLine.filterStencil(stencilRef);
        this.app.add(this.toStratLine);

        let backwayPath = [];
        let endPoint = linePath[linePath.length - 1].clone();
        backwayPath.push(endPoint);
        let airpotTopPosition = this.simulatorData.airportPosition.clone();
        if (endPoint.z < this.simulatorData.backHeight) {
            let topHeightPoint = endPoint.clone();
            topHeightPoint.z = this.simulatorData.backHeight;
            backwayPath.push(topHeightPoint);

            airpotTopPosition.z = this.simulatorData.backHeight;
        } else {
            airpotTopPosition.z = endPoint.z;
        }

        backwayPath.push(airpotTopPosition);
        backwayPath.push(this.simulatorData.airportPosition);
        dashLineData.pointArray = backwayPath;
        this.backwayLine = new Polyline(dashLineData);
        this.backwayLine.renderOrder = 2;
        this.backwayLine.filterStencil(stencilRef);
        this.app.add(this.backwayLine);

        path.unshift({ objPosition: this.simulatorData.simulatorInitPosition.toEPSGWeb() });
        path.unshift({ objPosition: this.simulatorData.airportPosition.toEPSGWeb() });
        for (let i = 1; i < backwayPath.length - 1; i++) {
            path.push({ objPosition: backwayPath[i].toEPSGWeb() });
        }
        let realTravelPath = [];
        path.forEach(element => {
            realTravelPath.push(element.objPosition.clone().toEPSGWeb());
        });
        pathLineData.pointArray = realTravelPath;
        pathLineData.lineWidth = 0;
        this.realTravelLine = new Polyline(pathLineData);

        let result = this.realTravelLine.intersectObjects(this.simulatorData.collisionObjs, this.simulatorData.sidewipeDistance || 2);
        if (result.intersectionPosition) {
            this.hasCollision = true;

            let tempPath = [];
            for (let i = 0; i <= result.previouseIndex; i++) {
                tempPath.push({ objPosition: realTravelPath[i] });
            }
            let endPoint = new Point(result.intersectionPosition.x, result.intersectionPosition.y, result.intersectionPosition.z, Const.EPSGType.EPSGWeb);
            if (result.intersectState == 1) { //有相交点，往反方向求出碰撞点
                let nextPoint = realTravelPath[result.nextIndex];
                let previousPoint = realTravelPath[result.previouseIndex];
                let direction = previousPoint.clone().sub(nextPoint).normalize();
                endPoint = endPoint.add(direction.multiplyScalar(this.simulatorData.sidewipeDistance || 2));
                tempPath.push({ objPosition: endPoint });
            } else {
                tempPath.push({ objPosition: endPoint });
            }

            path = tempPath;
            // this.wanderLine = null;
        } else {
            path.push({ objPosition: backwayPath[backwayPath.length - 1] });
        }

        return path;
    }

    private addLensflare() {
        const light: PointLight = new PointLight('#E1FFFF', 1, 0);
        this.objWandered.add(light);
        const textureLoader = new TextureLoader();

        const textureFlare0 = textureLoader.load(this.simulatorData.flickerImg);
        const lensflare = new Lensflare();
        lensflare.addElement(new LensflareElement(textureFlare0, 100, 0, light.color));
        light.add(lensflare);

        var countIndex = 0;
        setInterval(function () {
            if (countIndex % 2 == 0) {
                countIndex++;
                light.color.set('#FF0000');
            } else {
                countIndex = 0;
                light.color.set('#E1FFFF');
            }
        }, 500);
    }

    private flySimulator(path) {
        let objWander = new ObjWander(this.objWandered); //模型漫游的功能，该功能对模型的朝向有要求：模型的正面需要Z轴朝上
        this.app.mouse.addHoverObject(this.objWandered); //为该模型添加鼠标悬停的功能
        // this.app.mouse.removeHoverObject(this.objWandered); //为该模型移除鼠标悬停的功能
        let wanderOvercallback = this.wanderOverListener.bind(this);
        let wanderProgressCallback = this.wanderProgressListener.bind(this);
        let distance = 0;
        for (let i = 1; i < path.length; i++) {
            let previousPoint = path[i - 1].objPosition;
            let currentPoint = path[i].objPosition;
            distance += currentPoint.distanceTo(previousPoint);
        }
        let wanderTime = distance * (this.simulatorData.timeFactor || 50);
        objWander.wander(path, wanderTime, wanderOvercallback, wanderProgressCallback)
    }

    private wanderOverListener() {
        if (this.hasCollision == false) {
            // this.objWandered.position.copy(this.simulatorData.airportPosition.toEPSGWeb());
            this.objWandered.lookAt(new Point(0, 0, 0, Const.EPSGType.EPSGWeb));
        }

        let curPosition = this.objWandered.position;
        let newPoint = new Point(curPosition.x, curPosition.y, curPosition.z, Const.EPSGType.EPSGWeb);
        this.flyedPolyline.addPoint(newPoint);
    }

    private wanderProgressListener() {
        let curPosition = this.objWandered.position;
        let newPoint = new Point(curPosition.x, curPosition.y, curPosition.z, Const.EPSGType.EPSGWeb);
        this.flyedPolyline.addPoint(newPoint);
    }

    private drawFlyedLine(lineWidth, stencilRef) {
        let flyedLineData = {
            maxPoints: 30000,
            // pointArray: path,  //多边形的顶点数组
            color: '#F0A032',
            lineWidth: lineWidth,  //线的宽度
            transparent: true,
            opacity: 1,
            depthTest: true,
            stencilRef: stencilRef
        };
        this.flyedPolyline = new Polyline2(flyedLineData);
        this.flyedPolyline.renderOrder = 1;
        this.flyedPolyline.addPoint(this.simulatorData.airportPosition.toEPSGWeb());
        this.app.add(this.flyedPolyline);
    }

    public fly(path: Array<{ objPosition: Point }>, time: number, onFinishCallback?) {
        let linePath = [];
        path.forEach(element => {
            linePath.push(element.objPosition);
        });

        this.setPoi(linePath[0], linePath[linePath.length - 1]);

        let lineWidth = 3;
        let stencilRef = 5;

        path = this.addFlyLines(linePath, path, lineWidth, stencilRef);
        this.addLensflare();
        this.flySimulator(path);
        this.drawFlyedLine(lineWidth, stencilRef);

    }
}